/*
 * Copyright 2020 eBlocker Open Source UG (haftungsbeschraenkt)
 *
 * Licensed under the EUPL, Version 1.2 or - as soon they will be
 * approved by the European Commission - subsequent versions of the EUPL
 * (the "License"); You may not use this work except in compliance with
 * the License. You may obtain a copy of the License at:
 *
 *   https://joinup.ec.europa.eu/page/eupl-text-11-12
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * permissions and limitations under the License.
 */
package org.eblocker.lists.malware;

import org.eblocker.server.common.malware.MalwareEntry;
import org.eblocker.lists.tools.ResourceInputStream;
import org.eblocker.lists.util.HttpClient;
import org.eblocker.lists.util.HttpClientFactory;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

public class MalwareListCreator {
    private static final Logger log = LoggerFactory.getLogger(MalwareListCreator.class);

    private static final String PROPERTIES_FILE = "malware.properties";
    private static final String OUTPUT_FILTERED_URLS = "output.filtered.urls";
    private static final String OUTPUT_FILTERED_IP_PORTS = "output.filtered.ipPorts";

    private final ObjectMapper objectMapper;
    private final List<MalwareProvider> providers;
    private final String filteredUrlsOutput;
    private final String filteredIpPortsOutput;

    MalwareListCreator(Properties properties, ObjectMapper objectMapper, List<MalwareProvider> providers) {
        this.objectMapper = objectMapper;
        this.providers = providers;

        filteredUrlsOutput = properties.getProperty(OUTPUT_FILTERED_URLS);
        filteredIpPortsOutput = properties.getProperty(OUTPUT_FILTERED_IP_PORTS);
    }

    public static void main(String[] args) throws MalwareListException, IOException {
        ObjectMapper objectMapper = new ObjectMapper();
        Properties properties = loadProperties();
        HttpClient httpClient = HttpClientFactory.create();

        List<MalwareProvider> providers = Arrays.asList(
            //new MalwarePatrolProvider(properties, new MalwarePatrolDownloader(httpClient, new MalwarePatrolSanitizedUrlsParser(), properties), InetAddress::getAllByName),
            new PhishtankProvider(new PhishtankDownloader(properties, objectMapper, httpClient)),
            new FileProvider(properties, objectMapper)
        );

        new MalwareListCreator(properties, objectMapper, providers).run();
    }

    void run() throws MalwareListException {
        try {
            MalwareEntries entries = new MalwareEntries();

            for(MalwareProvider provider : providers) {
                MalwareEntries newEntries = provider.getMalwareEntries();
                log.debug("adding {} urls and {} ip / ports from {}", newEntries.getFilteredUrls().size(), newEntries.getFilteredIpPorts().size(), provider.getClass().getName());
                entries.merge(newEntries);
            }

            writeFilteredUrls(entries.getFilteredUrls());
            writeFilteredIpPorts(entries.getFilteredIpPorts());
        } catch (IOException e) {
            throw new MalwareListException("i/o error", e);
        }
    }

    private void writeFilteredUrls(List<MalwareEntry> filteredUrls) throws IOException {
        log.debug("writing {} entries to {}", filteredUrls.size(), filteredUrlsOutput);
        objectMapper.writeValue(new FileOutputStream(filteredUrlsOutput), filteredUrls);
    }

    private void writeFilteredIpPorts(Map<String, Set<Integer>> portsByIp) throws IOException {
        log.debug("writing {} ip / ports to {}", portsByIp.size(), filteredIpPortsOutput);
        objectMapper.writeValue(new FileOutputStream(filteredIpPortsOutput), portsByIp);
    }

    private static Properties loadProperties() throws IOException {
        log.debug("loading properties");
        Properties properties = new Properties();
        properties.load(ResourceInputStream.get(PROPERTIES_FILE));
        return properties;
    }
}
